//
// Created by Alex on 2022/3/27.
//

#include <stdexcept>
#include "core.h"

using namespace std;

vector<string> convert_words(char* words_in[], int len) {
    vector<string> words;
    words.reserve(len);
    for (int i = 0; i < len; i++) {
        words.emplace_back(words_in[i]);
    }
    return words;
}

int convert_result(vector<string>& result_vec, char* result[]) {
    int ret = (int)result_vec.size();
    if (ret > 20000) {
        return ret;
    }
    char* header = *result;
    int pos = 0;
    for (int i = 0; i < ret; i++) {
        if (pos + result_vec[i].size() + 1 >= 0x10000000) {
            fprintf(stderr, "Out of memory (128 MB)!\n");
            return ret;
        }
        result[i] = header + pos;
        for (char j : result_vec[i]) {
            header[pos++] = j;
        }
        header[pos++] = 0;
    }
    return ret;
}

int gen_chains_all(char* words[], int len, char* result[]) noexcept(false) {
    if (len <= 0) {
        throw invalid_argument("len should be large than 0.");
    }
    Solution solution(convert_words(words, len));
    vector<string> result_vec;
    if (solution.genAllChain(result_vec) == -1) {
        throw logic_error("There is a circle in the chain.");
    }
    return convert_result(result_vec, result);
}

int gen_chain_word(char* words[], int len, char* result[], char head, char tail, bool allow_circ) noexcept(false) {
    if (len <= 0) {
        throw invalid_argument("len should be large than 0.");
    }
    Solution solution(convert_words(words, len));
    vector<string> result_vec;
    if ('a' <= head && head <= 'z') {

    }
    else if ('A' <= head && head <= 'Z') {
        head = (char)(head + 0x20);
    }
    else if (head != '\0') {
        throw invalid_argument("Head is not a single letter.");
    }
    if ('a' <= tail && tail <= 'z') {

    }
    else if ('A' <= tail && tail <= 'Z') {
        tail = (char)(tail + 0x20);
    }
    else if (tail != '\0') {
        throw invalid_argument("Tail is not a single letter.");
    }
    if (solution.genMaxWordChain(result_vec, head, tail, allow_circ) == -1) {
        throw logic_error("There is a circle in the chain.");
    }
    return convert_result(result_vec, result);
}

int gen_chain_word_unique(char* words[], int len, char* result[]) noexcept(false) {
    if (len <= 0) {
        throw invalid_argument("len should be large than 0.");
    }
    Solution solution(convert_words(words, len));
    vector<string> result_vec;
    if (solution.genMaxWordChainNotSame(result_vec) == -1) {
        throw logic_error("There is a circle in the chain.");
    }
    return convert_result(result_vec, result);
}

int gen_chain_char(char* words[], int len, char* result[], char head, char tail, bool allow_circ) noexcept(false) {
    if (len <= 0) {
        throw invalid_argument("len should be large than 0.");
    }
    Solution solution(convert_words(words, len));
    vector<string> result_vec;
    if ('a' <= head && head <= 'z') {

    }
    else if ('A' <= head && head <= 'Z') {
        head = (char)(head + 0x20);
    }
    else if (head != '\0') {
        throw invalid_argument("Head is not a single letter.");
    }
    if ('a' <= tail && tail <= 'z') {

    }
    else if ('A' <= tail && tail <= 'Z') {
        tail = (char)(tail + 0x20);
    }
    else if (tail != '\0') {
        throw invalid_argument("Tail is not a single letter.");
    }
    if (solution.genMaxCharChain(result_vec, head, tail, allow_circ) == -1) {
        throw logic_error("There is a circle in the chain.");
    }
    return convert_result(result_vec, result);
}
int Add(int x, int y) {
    return x + y;
}